﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;

namespace ColorGame
{
   public static class ImageHelper
    {
        public static void FloodFill(Bitmap bmp, Point pt, Color fillcolor)
        {
            if (bmp.GetPixel(pt.X, pt.Y).ToArgb() != fillcolor.ToArgb())
            {

                byte[] m_Tolerance = new byte[] { 32, 32, 32 };
                bool[,] PixelsChecked;
                Queue CheckQueue = new Queue();

                BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                System.IntPtr Scan0 = bmpData.Scan0;
                unsafe
                {
                    byte* scan0 = (byte*)(void*)Scan0;
                    int loc = (bmpData.Stride * pt.Y) + (pt.X * 4);
                    int color = *((int*)(scan0 + loc));
                    PixelsChecked = new bool[bmpData.Width + 1, bmpData.Height + 1];
                    Size bmpsize = new Size(bmpData.Width, bmpData.Height);
                    CheckQueue = new Queue();
                    byte* btcolor2 = (byte*)&color;
                    if (!((pt.X < 0) || (pt.X >= bmpsize.Width) || (pt.Y < 0) || (pt.Y >= bmpsize.Height)))
                    {
                        int* p1 = (int*)(scan0 + (bmpData.Stride * pt.Y) + (pt.X * 4));
                        bool ret1 = true;
                        byte* px1 = (byte*)p1;//change point to byte
                        for (byte i = 0; i < 3; i++)
                        {
                            ret1 &= (px1[i] >= (btcolor2[i] - m_Tolerance[i])) && px1[i] <= (btcolor2[i] + m_Tolerance[i]);
                        }
                        if (!(PixelsChecked[pt.X, pt.Y]) && ret1)
                        {
                            //   p1[0] = m_fillcolor;   //fill with the color

                            p1[0] = fillcolor.ToArgb();

                            PixelsChecked[pt.X, pt.Y] = true;
                            CheckQueue.Enqueue(new Point(pt.X + 1, pt.Y));
                            CheckQueue.Enqueue(new Point(pt.X, pt.Y + 1));
                            CheckQueue.Enqueue(new Point(pt.X - 1, pt.Y));
                            CheckQueue.Enqueue(new Point(pt.X, pt.Y - 1));
                        }
                    }
                    while (CheckQueue.Count > 0)
                    {
                        Point pt2 = (Point)CheckQueue.Dequeue();
                        if (!((pt2.X < 0) || (pt2.X >= bmpsize.Width) || (pt2.Y < 0) || (pt2.Y >= bmpsize.Height)))
                        {
                            byte* btcolor = (byte*)&color;
                            int* p = (int*)(scan0 + (bmpData.Stride * pt2.Y) + (pt2.X * 4));
                            bool ret = true;
                            byte* px = (byte*)p;//change point to byte
                            for (byte i = 0; i < 3; i++)
                            {
                                ret &= (px[i] >= (btcolor[i] - m_Tolerance[i])) && px[i] <= (btcolor[i] + m_Tolerance[i]);
                            }
                            if (!(PixelsChecked[pt2.X, pt2.Y]) && ret)
                            {

                                p[0] = fillcolor.ToArgb();

                                PixelsChecked[pt2.X, pt2.Y] = true;
                                CheckQueue.Enqueue(new Point(pt2.X + 1, pt2.Y));
                                CheckQueue.Enqueue(new Point(pt2.X, pt2.Y + 1));
                                CheckQueue.Enqueue(new Point(pt2.X - 1, pt2.Y));
                                CheckQueue.Enqueue(new Point(pt2.X, pt2.Y - 1));
                            }
                        }
                    }
                }
                bmp.UnlockBits(bmpData);
            }
        }
    }
}
